#ifndef __BITSTREAM_H__
#define __BITSTREAM_H__

#include <vector>

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------

class OutputBitStream
{
 protected:

  std::vector<unsigned int> Data;
  unsigned int Mask,Value;

  //---------------------------------------------------------------------

 public:

  void Begin(void)	
    { 
      Data.resize(0); 
      Mask=0x00000001; 
      Value=0; 
    }

  //---------------------------------------------------------------------

  void PushBit(unsigned int bitValue)
    { 
      if (bitValue)
	Value|=Mask;
      Mask<<=1;	    

      if (!Mask)
	{
	  Data.push_back(Value);
	  Value=0;
	  Mask=0x00000001;
	}
    }

  //---------------------------------------------------------------------

  void PushValue(unsigned int value,unsigned int bitCount)
    { 
      for (unsigned int i=0,mask=1; i<bitCount; i++,mask<<=1)
	PushBit(value & mask);
    }

  //---------------------------------------------------------------------

  void End(void)	
    { 
      if (Mask!=0x00000001)
	{
	  Data.push_back(Value);
	  Mask=0x00000001; 
	}
    }

  //---------------------------------------------------------------------

  const unsigned int * GetData(void) const  { return &Data[0]; }    
  unsigned int GetDataSize(void) const { return (unsigned int)Data.size()*4; }    
};

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

//no overflow check, no endianess check, reads limited to 16 bits
class InputBitStream
{
 protected:

  unsigned short * Address;    
  unsigned int Value;
  unsigned int Remaining;

  //---------------------------------------------------------------------

 public:

  void Begin(unsigned short * address)	
    { 
      Address=address;
      Value=0;
      Remaining=0;
    }

  //---------------------------------------------------------------------

  unsigned int Read(unsigned int bitCount)	
    { 
      if (Remaining<16)
	{
	  unsigned int data=*Address++;
	  Value|=data << Remaining;
	  Remaining+=16;
	}

      return Value & ((1 << bitCount)-1);
    }

  //---------------------------------------------------------------------

  void Flush(unsigned int bitCount)	
    { 
      Value>>=bitCount;
      Remaining-=bitCount;
    }

  //---------------------------------------------------------------------

  unsigned int Pop(unsigned int bitCount)	
    { 
      unsigned int value = Read(bitCount);
      Flush(bitCount);
      return value;
    }
};

//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------

int CountBit(int value)
{
  int length=1;
  while(value & ( ~( (1<<length)-1 ) ))
    length++;
  return length;
}

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

//min input value : 0 encoded into 1 bit
//max input value : 2^31-2 encoded into 61 bits
void WriteExpGolomb(unsigned int value,OutputBitStream & stream)
{
  value++;//0 is encoded differently from other values
  int exp=0;
  while(value>>(exp+1))//exp is the number of bits of the value
    {
      stream.PushBit(1);
      exp++;
    }
  stream.PushBit(0);//end of unary representation of exp
  value-=1<<exp;//values with less than exp bits are encoded with less bits
  stream.PushValue(value,exp);
}

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------

void ReadExpGolomb(InputBitStream & stream,unsigned int & value)
{
  int exp=0;
  while(stream.Pop(1))
    exp++;
  value=stream.Pop(exp);
  value+=(1<<exp)-1;
}

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------

#endif //__BITSTREAM_H__
